#include "sock_msg_ctl.h"
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <linux/un.h>
#include "msg_def.h"
#include <pthread.h>
#include <string.h>
#include "gp_layout_map.h"
#include "gp_dp1_ctl.h"
#include "gp_dp8_ctl.h"
#include "gp_subboard_ctl.h"
#include "gp_dj_ctl.h"
#include "gp_qpcr_ctl.h"
#include "gp_openlid_ctl.h"
#include "gp_seal_ctl.h"
#include "gp_logistic_ctl.h"

int serverFd = -1;
int cliFd = -1;

int sock_exitFlag = 0;
int msgProc_exitFlag = 0;



msg_buff_list g_list_buff_msg;


void init_msg_buff_list(void)
{
    g_list_buff_msg.head = NULL;
    g_list_buff_msg.tail = NULL;

    pthread_t thread_handl;
    pthread_create(&thread_handl,NULL,msgProcFunc,NULL);
}

void clear_msg_buff_list(void)
{
    act_msg_node * ptrMsgNode = g_list_buff_msg.head;
    act_msg_node * ptrMsgNodePrev = ptrMsgNode;
    while(ptrMsgNode)
    {
        if(ptrMsgNode->paramData)
        {
            delete [] (char *)ptrMsgNode->paramData;
            ptrMsgNode->paramData = NULL;
        }
        ptrMsgNodePrev = ptrMsgNode;
        ptrMsgNode = ptrMsgNode->next;
        
        delete ptrMsgNodePrev;
        ptrMsgNodePrev = ptrMsgNode;
    }
}

pthread_mutex_t mutex_msg_mem = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_msg_data = PTHREAD_MUTEX_INITIALIZER;

int init_msg_buf_node(char * dataFromSock, int sockDataLen,act_msg_node ** nodeOut )
{
    if(sockDataLen<sizeof(sockActMsg))
    {
        * nodeOut = NULL;
        return 1;
    }
    sockActMsg msgNodeTemp;
    int offset = decodeMsgHead(dataFromSock,&msgNodeTemp);
    printf("in init_msg_buf_node, moduleType:%d,actType:%d,paramType:%d,paramLen:%d\n",
    msgNodeTemp.moduleType,
    msgNodeTemp.actType,
    msgNodeTemp.paramType,
    msgNodeTemp.paramLen);

    pthread_mutex_lock(&mutex_msg_mem);
    * nodeOut = new act_msg_node;
    memset(* nodeOut,0,sizeof(act_msg_node));
    memcpy(&((* nodeOut)->msgHead),&msgNodeTemp,sizeof(sockActMsg));
    pthread_mutex_unlock(&mutex_msg_mem); 

    if(msgNodeTemp.paramLen > 0)
    {
        pthread_mutex_lock(&mutex_msg_data);
        (* nodeOut)->paramData = new char[msgNodeTemp.paramLen];
        memcpy((* nodeOut)->paramData,dataFromSock+offset,msgNodeTemp.paramLen);        
        pthread_mutex_unlock(&mutex_msg_data);

    }
    return 0;   
}

void append_msg_buff_node(act_msg_node * nodeIn)
{
    if(g_list_buff_msg.head == NULL)
    {
       g_list_buff_msg.head = nodeIn;
       g_list_buff_msg.tail = nodeIn;
    }
    else if(g_list_buff_msg.tail)
    {
       g_list_buff_msg.tail->next = nodeIn;
       g_list_buff_msg.tail = g_list_buff_msg.tail->next;
    }
}

act_msg_node* get_msg_buff_head(void)
{
    act_msg_node* nodeRet = NULL;
    if(g_list_buff_msg.head)
    {
       nodeRet = g_list_buff_msg.head;
       g_list_buff_msg.head = g_list_buff_msg.head->next;
       if(g_list_buff_msg.head == NULL)
       {
           g_list_buff_msg.tail = NULL;
       }
    }
    return nodeRet;
}

void * sockRecvFunc(void * paramIn)
{
    fd_set rfds;
    struct timeval tv;
    int retval;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    struct sockaddr_un client_addr;
    socklen_t client_len = 0;
    char recvBuff[512];
    int recvLen = 0;
    while(!sock_exitFlag)
    {
       if(cliFd<0)
       {
           if(serverFd>0)
           {
               cliFd = accept(serverFd, (struct sockaddr *)&client_addr, &client_len);
               
           }
           else
           {
               initSockServer(0);
           }
       }
       else
       {
            FD_ZERO(&rfds);
            
            FD_SET(cliFd, &rfds);
            tv.tv_sec = 2;
            tv.tv_usec = 0;
            retval = select(cliFd+1,&rfds,NULL,NULL,&tv);

            if(retval<0)
            {
                perror("select()");
                close(cliFd);
                cliFd = -1;
            }
            else if(retval==0)
            {
                //no data available in 2 second;
            }
            else
            {
                //data received;
                if(FD_ISSET(cliFd, &rfds))
                {
                    recvLen = 0;
                    //printf("received data in sockRecvFunc,");
                    recvLen = read(cliFd,recvBuff,512);

                    //printf("recvLen:%d\n",recvLen);

                    if(recvLen>0)
                    {
                        sockActMsg msgRecv;
                        //parseMsg(recvBuff,recvLen,&msgRecv);
                        
                        //printf("parse end\n");
                        // printf("moduletype:%d,actType:%d,paramType:%d,paramlen:%d\n",
                        // msgRecv.moduleType,
                        // msgRecv.actType,
                        // msgRecv.paramType,
                        // msgRecv.paramLen);
                        act_msg_node * pstActMsgNode = NULL;
                        init_msg_buf_node(recvBuff,recvLen,&pstActMsgNode);

                                    
                        if(pstActMsgNode!=NULL)
                        {
            //                 printf("in sockRecvFunc, node[%x],moduleType:%d,actType:%d,paramType:%d,paramlen:%d\n",
            // pstActMsgNode,
            // pstActMsgNode->msgHead.moduleType,
            // pstActMsgNode->msgHead.actType,
            // pstActMsgNode->msgHead.paramType,
            // pstActMsgNode->msgHead.paramLen);

                            append_msg_buff_node(pstActMsgNode);
                        }                       

                    }
                    else
                    {
                        //the romote sock closed.
                        close(cliFd);
                        cliFd = -1;
                    }
                    
                }
            }
       }
       usleep(100);       
    } 

   pthread_detach(pthread_self());

   return (void*)NULL;
}


void * msgProcFunc(void * paramIn)
{
    act_msg_node * msgNode = NULL;

    while(!msgProc_exitFlag)
    {       
       msgNode = get_msg_buff_head();

       if(msgNode)
       {
            //proc msg here.
            // printf("in msgProcFunc, node[%x],moduleType:%d,actType:%d,paramType:%d,paramlen:%d\n",
            // msgNode,
            // msgNode->msgHead.moduleType,
            // msgNode->msgHead.actType,
            // msgNode->msgHead.paramType,
            // msgNode->msgHead.paramLen);
            pthread_t thread_handle;
            pthread_create(&thread_handle,NULL,actMsgProc,msgNode);
       }
       else
       {
            usleep(1000);
       }

    } 

   pthread_detach(pthread_self());

   return (void*)NULL;
}

pthread_mutex_t mutex_sock_send = PTHREAD_MUTEX_INITIALIZER;

int sendAckResponse(msgAckSock * actResult)
{
    int retVal = 0;
    if(cliFd > 0)
    {
        pthread_mutex_lock(&mutex_sock_send);
        write(cliFd,actResult,sizeof(msgAckSock));
        pthread_mutex_unlock(&mutex_sock_send);
    }
    return retVal;
}

const moduleActFunc moduleActionArr[MODULE_MAX_NUM] = 
{
    djActFunc,
    djActFunc,
    dp1ActFunc,
    dp8ActFunc,
    sealActFunc,
    subboardActFunc,
    openlidActFunc,
    qpcrActFunc,
    qpcrActFunc,
    subboardActFunc,
    subboardActFunc,
    subboardActFunc,
    dp8_1ActFunc,
    logisticActFunc,
};

void* actMsgProc(void * msgIn)
{
    act_msg_node * pstActMsgNode = (act_msg_node *)msgIn;
    pthread_detach(pthread_self());
    msgAckSock actResult;
    memset(&actResult,0,sizeof(msgAckSock));
    actResult.moduleType = pstActMsgNode->msgHead.moduleType;
    actResult.actType = pstActMsgNode->msgHead.actType;
    if(actResult.actType == ACT_SINGLE_MOVE 
    || actResult.actType == ACT_SINGLE_INIT
    || actResult.actType == ACT_SCANCODE_CTL
    || ACT_PLUNGER_PUMP == actResult.actType
    )
    {
        memcpy(&actResult.component,pstActMsgNode->paramData,sizeof(int));
    }
    else if(actResult.actType == ACT_DJ_CLEAN_CTL
         || actResult.actType == ACT_DRAWER_CTL
         || actResult.actType == ACT_TEMPERATURE_READ
         || actResult.actType == ACT_SHAKE_CTL
         || actResult.actType == ACT_HEAT_CTL
         || actResult.actType == ACT_LIGHT_CTL
         )
    {
        actResult.component = pstActMsgNode->msgHead.paramType;
    }
    else
    {
        actResult.component = -1;
    }

    

    //here is the real action.
    //using function pointer to exeute different action of different module
    if(actResult.moduleType < MODULE_MAX_NUM
    &&actResult.moduleType >= 0
    &&moduleActionArr[actResult.moduleType])
    {
        moduleActionArr[actResult.moduleType](pstActMsgNode,&actResult);
    }    
    printf("in actMsgProc,send response now\n");    
    sendAckResponse(&actResult);
    //printf("in actMsgProc,release memory now\n");
    if(pstActMsgNode->paramData)
    {
        pthread_mutex_lock(&mutex_msg_data);
        delete [] (char*)pstActMsgNode->paramData;
        pstActMsgNode->paramData = NULL;
        pthread_mutex_unlock(&mutex_msg_data);
    }
    pthread_mutex_lock(&mutex_msg_mem);
    delete pstActMsgNode;
    pstActMsgNode=NULL;
    pthread_mutex_unlock(&mutex_msg_mem);

    printf("exit actMsgProc\n");
    
    return (void*)NULL;
}

int initSockServer(int needCreateThread)
{
    socklen_t client_len = 0;
 
    struct sockaddr_un server_addr;
    struct sockaddr_un client_addr;
 
    // 创建流套接字
    serverFd = socket(AF_UNIX, SOCK_STREAM, 0);

    unlink(SOCK_IPC_FILE);
 
    // 设置服务器接收的连接地址和监听的端口
    server_addr.sun_family = AF_UNIX;                   // 指定网络套接字
    snprintf(server_addr.sun_path,sizeof(server_addr.sun_path),"%s",SOCK_IPC_FILE);
 
    // 绑定（命名）套接字
    bind(serverFd, (struct sockaddr *)&server_addr, sizeof(sockaddr_un));
 
    // 创建套接字队列，监听套接字
    listen(serverFd, 5);
    
    if(needCreateThread)
    {
        pthread_t thread_handle;
        pthread_create(&thread_handle,NULL,sockRecvFunc,NULL);
    }   
 
    // 忽略子进程停止或退出信号
    //signal(SIGCHLD, SIG_IGN);
    return 0;
}

int decodeInt(char * buffIn)
{
    int retVal = 0;
    memcpy(&retVal,buffIn,sizeof(int));

    return retVal;
}

int decodeMsgHead(char * buffIn, void * msgHeadOut)
{
    sockActMsg * ptrMsgHead = (sockActMsg *)msgHeadOut;
    char *ptrBuff = buffIn;
    int lenInt = sizeof(int); 

    ptrMsgHead->moduleType =  decodeInt(ptrBuff);
    ptrBuff += lenInt;
    ptrMsgHead->actType =  decodeInt(ptrBuff);
    ptrBuff += lenInt;
    ptrMsgHead->paramType = decodeInt(ptrBuff);
    ptrBuff += lenInt;
    ptrMsgHead->paramLen = decodeInt(ptrBuff);

    return 4*lenInt;

}

int parseMsg(char * msgBuff, int msgLen,void * msgHeadOut)
{
    sockActMsg * ptrMsgHead = (sockActMsg *)msgHeadOut;
    printf("enter in parseMsg,msgLen:%d,sizehead:%d\n",msgLen,sizeof(sockActMsg));
    if(msgLen<sizeof(sockActMsg))
    {
        return 1;
    }

    decodeMsgHead(msgBuff, msgHeadOut);
    printf("leave parseMsg\n");
}